package com.imooc.business.core.executor.up;

import com.imooc.module.exception.DataCenterException;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @Author Tim
 * @Description: 升级维度事件构造器 建造者模式
 * @Version 1.0
 */
@Slf4j
public class EventProcessBuilder {
    /**
     * 默认实现，RocketMqEventProcess
     */
    private Class<? extends EventProcess> implementClass;

    /**
     * 装饰者，方面我们进行业务扩展
     */
    private final List<Class<? extends EventProcess>> decorators;

    public EventProcessBuilder() {
        this.decorators = new ArrayList<>();
    }

    public EventProcessBuilder implementClass(Class<? extends EventProcess> implementClass) {
        this.implementClass = implementClass;
        return this;
    }

    public EventProcessBuilder addDecorator(Class<? extends EventProcess> decorator) {
        if (Objects.nonNull(decorator)) {
            this.decorators.add(decorator);
        }
        return this;
    }

    public EventProcess build() {
        //设置默认执行器实现
        setDefaultImplementClass();
        //实例化默认执行器
        EventProcess process = newBaseEventProcessInstance(this.implementClass);

        for (Class<? extends EventProcess> decorator : this.decorators) {
            //责任链调用
            process = newEventProcessDecoratorInstance(decorator, process);
        }
        return process;
    }

    private EventProcess newEventProcessDecoratorInstance(Class<? extends EventProcess> decorator, EventProcess process) {
        try {
            return decorator.getDeclaredConstructor(EventProcess.class).newInstance(process);
        } catch (Exception e) {
            log.error("newEventProcessDecoratorInstance, instance fail, e=",e);
            throw new DataCenterException("newEventProcessDecoratorInstance instance fail");
        }
    }

    /**
     * 根据构造器进行反射，创建实例
     * @param implementClass
     * @return
     */
    private EventProcess newBaseEventProcessInstance(Class<? extends EventProcess> implementClass) {
        try {
            return implementClass.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            log.error("newBaseEventProcessInstance, instance fail, e=",e);
            throw new DataCenterException("newBaseEventProcessInstance instance fail");
        }
    }

    private void setDefaultImplementClass() {
        if (Objects.isNull(this.implementClass)) {
            this.implementClass = RocketMqEventProcess.class;
        }
    }
}
